package main

import (
	"fmt"
	"log"
	mrand "math/rand"
	"strconv"
	"strings"
	"time"
)

func VerifyActiveCode(active_code string) (bool, int, string) {
	key := []byte(GetMD5Encode(SecreteKey))
	machine_code, ok := AESDecrypt(key, active_code)
	if !ok {
		log.Fatal("Verify Decrypt failed")
	}
	use_code := ""
	//fmt.Println(machine_code)
	// 去除尾部随机字符串
	for i, v := range machine_code {
		if i >= len(machine_code)-len(SecreteKey) {
			break
		}
		use_code += string(v)
	}

	var expire_time int
	//fmt.Println(use_code)
	//fmt.Println(use_code[16:17])
	switch use_code[16:17] {
	case "E":
		expire_time = 86400
	case "X":
		expire_time = 604800
	case "N":
		expire_time = 2628000
	case "P":
		expire_time = 31536000
	case "Q":
		// TODO 这里如果是-1就要考虑续签的问题，如果先上面的数据之后-1续签，则会导致没有效果;目前后面的过期时间都是根据int来做的，如果是-1会造成诸多bug，考虑用其他的替换
		expire_time = -1
	default:
		log.Fatal("verify failed")
	}
	// 机器码校验
	machine_code_hash := use_code[:16]
	ok, this_machine_code := GenericMachineCode()
	if !ok || machine_code_hash != this_machine_code {
		log.Fatal("verify failed")
	}
	//fmt.Println(expire_time)

	// 激活码存入
	if !CheckActive(active_code) {
		log.Fatal("verify failed")
	}
	AppendFile(RecordActive, active_code)
	// 读取api_info
	api_info := use_code[17:]

	// 判定是否是无期限，如果是无期限flag置位-1
	ext_flag := 1
	if expire_time == -1 {
		ext_flag = -1
		// 无期限 time生成随机数值防止破解
		r := mrand.New(mrand.NewSource(time.Now().UnixNano()))
		expire_time = r.Intn(65535) + 1  // +1防止为0
	}
	// 如果是续签，计算过期时间总值
	if CheckFileIsExist(LicensePath) {
		md5_e_time := strings.Split(ReadFile(MD5Path), "\n")[0]
		etime, ok := AESDecrypt(key, md5_e_time[32:])
		if !ok {
			log.Fatal("verify failed")
		}
		int_expire_time, _ := strconv.Atoi(etime)
		if int_expire_time < 0 && ext_flag == 1{  // 如果之前是无限期，又给了有限期的激活码，则报错
			log.Fatal("already unlimited, don't active limit again")
		}
		if int_expire_time < 0 {
			// 之前是无限期，本次还是无限期，则不再进行时间叠加，只更新api info信息
		} else {
			expire_time += int_expire_time - int(time.Now().Unix())
		}
	}
	fmt.Println("expire_time=============")
	fmt.Println(expire_time)
	fmt.Println("ext_flag=============")
	fmt.Println(ext_flag)
	expire_time *= ext_flag
	return true, expire_time, api_info
}

func GetTimeFromFile() (string, string, string) {
	now_time := ReadFile(LicensePath)
	// 校验文件md5
	md5_res, err := CalcFileMD5(LicensePath)
	if err != nil {
		log.Fatal("license md5 failed")
	}
	md5_res2, err := CalcFileMD5(RecordActive)
	if err != nil {
		log.Fatal("license md5 failed")
	}
	//fmt.Println("now_time", now_time)
	res2 := strings.Split(ReadFile(MD5Path), "\n")
	md5_e_time, api_info := res2[0], res2[1]
	//fmt.Println("1111", md5_e_time)
	//fmt.Println("2222", api_info)
	if Get16MD5Encode(md5_res) != md5_e_time[:16] {
		log.Fatal("md5 verify failed1")
	}
	fmt.Println("------------------------")
	fmt.Println(Get16MD5Encode(md5_res2))
	fmt.Println(md5_e_time[16:32])
	fmt.Println("------------------------")
	if Get16MD5Encode(md5_res2) != md5_e_time[16:32] {
		log.Fatal("md5 verify failed2")
	}

	api_info, ok := AESDecrypt([]byte(GetMD5Encode(SecreteKey)), api_info)
	if !ok {
		log.Fatal("decrypt api_info failed")
	}

	return now_time, md5_e_time, api_info
}

func CheckFlag() bool {
	ok, QueryRes := ExecCommand("cat", "/root/.bashrc")

	if !ok {
		log.Fatal("license failed")
	}
	flag := false
	for _, data := range QueryRes {
		if strings.Index(data, "SYSENV") != -1 {
			flag = true
		}
	}
	if !CheckFileIsExist(LicensePath) {
		// 文件不存在，当第一次激活码激活时,考虑是否是用户进行了删除操作？
		/*
			如果是第一次激活，向~/.bashrc中写入flag环境变量，之后每次检查flag，如果有flag而没有文件，则为用户恶意删除
		*/
		if flag == true { // 如果没有license，但是bashrc里面有flag，则license文件被损坏或删除（有可能bashrc里面一起被清除的情况，暂不考虑）
			log.Fatal("license failed")
		}
		AppendFlagToBashrc()
	} else {
		// 已经生成了文件，两种可能，一种是续签，一种是每次查询，这里是检查flag逻辑
		if flag == false { // 如果有文件，没有flag，不排除bashrc被动过，自动再加上就是了——这里不判错的原因是bashrc是一个改动频繁的文件，不能保证用户不进行更改
			AppendFlagToBashrc()
		}
	}
	return true
}

func VerifyLicenseFile() {
	if !CheckFileIsExist(LicensePath){
		log.Fatal("verify failed")
	}

	secret_key := GetMD5Encode(SecreteKey)
	var key = []byte(secret_key)
	//fmt.Println(key)
	now_time, md5_e_time, api_info := GetTimeFromFile()
	//now_time = DeleteStringSth(now_time, []string{" ", "\n"}, -1)
	//md5_e_time = DeleteStringSth(md5_e_time, []string{" ", "\n"}, -1)
	o_now_time, ok := AESDecrypt(key, now_time)
	if !ok {
		log.Fatal("verify failed")
	}

	etime, ok := AESDecrypt(key, md5_e_time[32:])
	if !ok {
		log.Fatal("verify failed")
	}

	//fmt.Println("now_time:==>", now_time, "<==md5_e_time:==>", md5_e_time[32:], "<==")
	//fmt.Println("type of now_time ", reflect.TypeOf(now_time))
	//fmt.Println("111111111111111111111", o_now_time, "111111111111111111111", etime, "111111111111111111111", exp)

	// 获取到两个文件中的时间，之后进行时间的判断，当前时间是否小于now_time?是否大于exp time?now_time文件md5值是否准确？record active md5值是否准确？
	int_old_now_time, _ := strconv.Atoi(o_now_time)
	int_expire_time, _ := strconv.Atoi(etime)

	// TODO 如果是无限期的情况？
	if int_expire_time < 0 {
		fmt.Println("---------------------------")
		fmt.Println(int_expire_time)
		fmt.Println("---------------------------")

		// TODO 想一下无限期情况有没有需要校验的？没有，但是API info需要重新封装
		fmt.Println(api_info)
	} else {
		now_time64 := time.Now().Unix()
		int_now_time := int(now_time64)
		fmt.Println("---------------------------")
		fmt.Println(int_expire_time)
		fmt.Println("剩余时间：", int_expire_time-int_now_time)
		fmt.Println("---------------------------")
		/* md5值校验，其实在上面GetTimeFromFile已经校验过一回，没必要再来一遍，但是record active md5需要校验(已经在GetTimeFromFile进行校验)
		md5_res, err := CalcFileMD5(LicensePath)
		if err != nil {
			log.Fatal("license md5 failed")
		}
		if Get16MD5Encode(md5_res) != md5_e_time[:16] {
			log.Fatal("md5 verify failed")
		}*/
		/* DEBUG time
		fmt.Println("---------------------------")
		fmt.Printf("int_now_time:\t%d\n", int_now_time)
		fmt.Printf("int_old_now_time:\t%d\n", int_old_now_time)
		fmt.Printf("int_expire_time:\t%d\n", int_expire_time)
		fmt.Println("---------------------------")
		 */

		// int_now_time这里不能判断=int old now time，否则并发高的情况会一直显示激活码失效
		if int_now_time < int_old_now_time || int_now_time > int_expire_time {
			// TODO 思考下是否还有其它需要校验的时间逻辑？
			log.Fatal("active_code expire")
		}
		// 输出API INFO
		//fmt.Println("---------------------------")
		fmt.Println(api_info)
		//fmt.Println("---------------------------")

		// ！这里的激活码好像不是很必要，因为已经有了激活码文件，是否用其它东西替换这里的内容？  可以考虑用record active文件的md5值代替（已经完成替换，使用API INFO替换原来激活码）
		// api_info对称加密，因为每次校验API都必须能够取出，所以这里必须先在上面解密，在这里再次加密，取出未加密API INFO返回给用户
		api_info, ok = AESEncrypt([]byte(secret_key), api_info)
		if !ok {
			log.Fatal("api_info encrypt is failed")
		}
		// 如果时间没有问题，进行下一步操作，把license的now_time替换为当前时间，重新计算md5值，生成新的license附属文件
		SaveTimeToFile(now_time64, int64(int_expire_time), api_info)
		}
		// TODO 是否需要返回值?
}

func CheckActive(active string) bool {
	if !CheckFileIsExist(RecordActive) {
		log.Fatal("record file breakdown")
	}
	ok2, res := ExecCommand("cat", RecordActive)
	if !ok2 {
		log.Fatal("Get ACTIVE Failed")
	}
	for _, v := range res {
		if strings.Index(v, active) != -1 {
			//fmt.Println("debugged 1", res[len(res)-1:][0])
			//fmt.Println("debugged 2", res[len(res)-2 : len(res)-1][0])
			if v == res[len(res)-1:][0] {
				log.Fatal("active again?")
			} else {
				log.Fatal("active code expired")
			}
		}
	}
	return true // 返回True表示激活码没有在里面，可以正常激活
}
